#include "plc2llvm/PLCScope.h"
#include "plc2llvm/PLCScopeStack.h"

void PLCScope::setImportSymbol(ImportScope *importSymbol) {
    this->importSymbol = importSymbol;
}

ImportScope *PLCScope::getImportSymbol() {
    return this->importSymbol;
}

void PLCScope::setSymbolTable(PLCSymbolTable *symbolTable) {
    this->symbolTable = symbolTable;
}

PLCSymbolTable *PLCScope::getSymbolTable() {
    return this->symbolTable;
}

void PLCScope::setParentScope(PLCScope *parentScope) {
    this->parentScope = parentScope;
}

PLCScope *PLCScope::getParentScope() {
    return this->parentScope;
}

void PLCScope::addChildScope(PLCScope *childScope) {
    this->childScopes.push_back(childScope);
}

std::vector<PLCScope *> &PLCScope::getChildScopes() {
    return this->childScopes;
}

void PLCScope::addUsingNamespaceList(PLCScope *usedNamespace) {
    //记录作用域
    this->usingNamespaceList.push_back(usedNamespace);
    //添加备选符号
    PLCSymbolTable* namespaceSymbolTable = usedNamespace->getSymbolTable();
    this->symbolTable->addAlternativeSymbolsFromTable(namespaceSymbolTable);
}

std::vector<PLCScope *> &PLCScope::getUsingNamespaceList() {
    return this->usingNamespaceList;
}

PLCSymbol *PLCScope::findSymbolByNameFromLocal(std::string name) {
    return this->symbolTable->getSymbolByNameFromLocalNameMap(name);
}

PLCSymbol* PLCScope::findSymbolByNameFromAll(std::string name) {
    return this->symbolTable->getSymbolByNameFromLocalRecord(name);
}



PLCScope::PLCScope(ImportScope *importSymbol, PLCScope *parentScope) :
    importSymbol(importSymbol), parentScope(parentScope),
    symbolTable(new PLCSymbolTable(importSymbol, this)) {
    //添加父作用域的符号
    PLCSymbolTable* parentScopeSymbolTable = parentScope->getSymbolTable();
    this->symbolTable->addAlternativeSymbolsFromTable(parentScopeSymbolTable);
}

PLCScope::PLCScope(ImportScope *importSymbol) :
    importSymbol(importSymbol), parentScope(PLCScopeStack::getTopScope()),
    symbolTable(new PLCSymbolTable(importSymbol, this)) {
    //添加父作用域的符号
    PLCSymbolTable* parentScopeSymbolTable = parentScope->getSymbolTable();
    this->symbolTable->addAlternativeSymbolsFromTable(parentScopeSymbolTable);
}

PLCScope::PLCScope() :
    importSymbol(nullptr), parentScope(nullptr),
    symbolTable(new PLCSymbolTable(importSymbol, this)){

}

void PLCScope::addLocalSymbol(PLCSymbol *localSymbol) {
    this->symbolTable->addFromLocal(localSymbol);
}

PLCSymbol *PLCScope::findSymbolFromLocal(std::string name) {
    return this->symbolTable->getSymbolByNameFromLocalNameMap(std::move(name));
}

PLCSymbol *PLCScope::findSymbolFromAll(std::string name) {
    PLCSymbol* target = nullptr;

    target = this->symbolTable->getSymbolByNameFromLocalRecord(name); //在本作用域的符号表内寻找此名称的符号
    if(target) //找到则返回，在本地找到不需要记录
        return target;

    //如果要查找的作用域不是全局作用域(设定全局作用域的父作用域指针为nullptr),那么在父作用域内查找，找到则返回
    if(this->parentScope != nullptr){
        target = this->findSymbolFromAll(name);
        if(target){
            this->symbolTable->addAlternativeSymbol(target); //将找到的符号与本地的同名符号链接起来
            return target;
        }

    }
    for(auto* scope : this->usingNamespaceList){ //在使用的命名空间内查找，找到则返回
        target = scope->findSymbolFromAll(name);
        if(target){
            this->symbolTable->addAlternativeSymbol(target); //将找到的符号与本地的同名符号链接起来
            return target;
        }
    }
    return target;
}


